package com.yanggu.jt808.entity.gpsdata;

import com.yanggu.jt808.util.Jt808Constant;
import com.yanggu.jt808.util.Jt808Util;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import lombok.Data;
import lombok.NoArgsConstructor;


/**
 * @author 杨顾
 */
@Data
@NoArgsConstructor
public class DataPackage {

    /**
     * 消息头
     */
    protected Header header = new Header();

    /**
     * 消息体
     */
    protected ByteBuf msgBody;

    public DataPackage(ByteBuf msgBody) {
        this.msgBody = msgBody;
    }

    /**
     * 解析方法
     */
    public void parseHeader() {
        //1. 解析消息头
        //获取消息ID(2个字节)
        int msgId = msgBody.readUnsignedShort();
        //将10进制的msgId转换成16进制
        msgId = Integer.parseInt(Integer.toHexString(msgId), 16);
        header.setMsgId(msgId);
        //获取消息体属性(2个字节)
        header.setMsgBodyProps(msgBody.readUnsignedShort());
        //设置是否加密
        header.setEncryptionType((byte) ((header.msgBodyProps & 0x1c00) >> 10));
        //设置是否是2019年版本
        header.setVersion2019(((header.getMsgBodyProps() & 0x4000) >> 14) == 1);
        if (header.isVersion2019()) {
            //2019年协议新增协议版本号(1个字节)
            header.setProtocolVersion(msgBody.readUnsignedByte());
            //2019年协议终端手机号为10个字节
            header.setTerminalPhone(Jt808Util.bcdToString(readBytes(10)));
        } else {
            //2011、2013年协议终端手机号为6个字节
            header.setTerminalPhone(Jt808Util.bcdToString(readBytes(6)));
        }
        //获取终端的消息流水号(2个字节)
        header.setFlowId(msgBody.readUnsignedShort());
        //是否有分包
        boolean subPackage = ((header.getMsgBodyProps() & 0x2000) >> 13) == 1;
        if (subPackage) {
            header.setSubPackage(true);
            //消息总包数(2个字节)
            header.setTotalPackage(msgBody.readUnsignedShort());
            //包序号(2个字节)
            header.setPackageNumber(msgBody.readUnsignedShort());
        }
        //2. 验证包体长度
        //消息头中消息体属性消息长度是否等于剩余可读字节
        if (header.getMsgBodyLength() != msgBody.readableBytes()) {
            throw new RuntimeException("包体长度有误");
        }
    }

    /**
     * 请求报文重写
     */
    protected void parseBody() {
        //子类重写该方法
    }

    /**
     * 响应报文重写 并调用父类
     *
     * @return
     */
    public ByteBuf toByteBufMsg() {
        //在JT808Encoder escape()方法处回收
        ByteBuf byteBuf = ByteBufAllocator.DEFAULT.heapBuffer();
        //设置消息ID
        byteBuf.writeShort(header.getMsgId());

        //是否分包
        boolean subPackage = header.isSubPackage();
        int subPkg = subPackage ? 1 : 0;
        //是否是2019年版本
        boolean version2019 = header.isVersion2019();
        int is2019 = version2019 ? 1 : 0;
        //消息体长度
        int msgLength = msgBody.readableBytes();
        //构建消息体属性(消息体长度、数据加密方式、分包、是否为2019年协议、保留字段)
        short msgBodyProps = (short) (((msgLength & 0x3FF) | (header.getEncryptionType() << 10 & 0x1C00) | ((subPkg << 13) & 0x2000) | ((is2019 << 14) & 0xC000)) & 0xffff);
        //设置消息体属性
        byteBuf.writeShort(msgBodyProps);
        if (version2019) {
            byteBuf.writeByte(header.getProtocolVersion());
        }
        //需要转换成BCD码, 6个字节或者10个字节
        byteBuf.writeBytes(Jt808Util.toBcdBytes(header.getTerminalPhone()));
        //设置消息流水号(2个字节)
        byteBuf.writeShort(header.getFlowId());
        //根据是否分包设置总包数和包序号(分贝时2个字节)
        if (header.isSubPackage()) {
            byteBuf.writeShort(header.getTotalPackage());
            byteBuf.writeShort(header.getPackageNumber());
        }
        //写入消息体
        byteBuf.writeBytes(this.msgBody);
        return byteBuf;
    }

    /**
     * 从ByteBuf中read固定长度的数组,相当于ByteBuf.readBytes(byte[] dst)的简单封装
     *
     * @param length
     * @return
     */
    protected byte[] readBytes(int length) {
        byte[] bytes = new byte[length];
        msgBody.readBytes(bytes);
        return bytes;
    }

    /**
     * 从ByteBuf中读出固定长度的数组 ，根据808默认字符集构建字符串
     *
     * @param length
     * @return
     */
    public String readString(int length) {
        return new String(readBytes(length), Jt808Constant.DEFAULT_CHARSET);
    }

    /**
     * 消息头16个字节(2019年版协议为20个字节)
     */
    @Data
    public static class Header {

        /**
         * 消息ID 2字节(由于是无符号使用大的数据类型存放)
         */
        private int msgId;

        /**
         * 消息体属性 2字节(由于是无符号使用大的数据类型存放)
         */
        private int msgBodyProps;

        /**
         * 协议版本号 1字节(2019年协议, 新增字段)(由于是无符号使用大的数据类型存放)
         */
        private short protocolVersion;

        /**
         * 是否是2019年协议
         */
        private boolean isVersion2019;

        /**
         * 终端手机号 6字节(2019年版协议为10字节) BCD码
         */
        private String terminalPhone;

        /**
         * 流水号 2字节(由于是无符号使用大的数据类型存放)
         */
        private int flowId;

        /**
         * 消息总包数 2字节(由于是无符号使用大的数据类型存放)
         */
        private int totalPackage;

        /**
         * 包序号 2字节(由于是无符号使用大的数据类型存放)
         */
        private int packageNumber;

        /**
         * 是否分包
         */
        private boolean isSubPackage;

        /**
         * 加密类型 3字节
         */
        private byte encryptionType;

        //获取包体长度
        public short getMsgBodyLength() {
            return (short) (msgBodyProps & 0x3ff);
        }

    }

}
